// KSP_Exec.cpp : Defines the entry point for the console application.
//

#define USE_CAS_DATASET
#define USE_OLD_DAT_NOTATION
#define USE_OLD_FILESYSTEM

//#include <tchar.h>
//#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>

#include <vbl/Exception.h>
#include <vbl/img/io/ImageIO.h>
#include <vbl/util/Array2D.h>
#include <vbl/calib/BogUtils.h>
#include <vbl/img/proc/Demosaic.h>
#include <vbl/img/ImageTransform.h>
#include <vbl/img/ImageDraw.h>

#include <boost/lexical_cast.hpp>
#include <boost/progress.hpp>
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>

#include "KSP.h";
#include "HelperFunctions.h"
#include "MCG_dataset.h"

namespace bf = boost::filesystem;
namespace MCG = datasets::MCG;

using namespace std;
using namespace boost;
using namespace vbl;

struct rectangle 
{
	bool isVisible;
	int xmin;
	int xmax;
	int ymin;
	int ymax;
};

struct cutOutInfo 
{ 
	rectangle r;
	int pathNr;
	img::ImageRGB imageCutOut;
};

void readConfigFile(string config_file_path, string & scenario_name, string & proba_path, string & image_path, 
					string & background_path, string & pom_file, string & output_path, string & bog_path, int & pom_x, 
					int & pom_y, int & begin_frame, int & num_of_frames, int & batch_size, double & passProb)
{
	ifstream config_file(config_file_path.c_str());
	bool sn = false, pp = false, ip = false, bp = false, pf = false, op = false, px = false, py = false, bf = false, 
		nof = false, bs = false, bogp = false, pap = false;

	if(!config_file.is_open())
	{
		throw vbl::runtime_error( "[readConfigFile] Config file not found: " + config_file_path );
	} 
	else 
	{
		static enum StringValue 
		{
			eSN,
			ePP,
			eIP,
			eBP,
			ePF,
			eOP,
			ePX,
			ePY,
			eBF,
			eNOF,
			eBS,
			eBOGP,
			ePAP
		};

		static map<std::string, StringValue> entryMap;
		entryMap["SCENARIONAME"] = eSN;
		entryMap["PROBAPATH"] = ePP;
		entryMap["IMAGEPATH"] = eIP;
		entryMap["BACKGROUNDPATH"] = eBP;
		entryMap["POMFILE"] = ePF;
		entryMap["OUTPUTPATH"] = eOP;
		entryMap["POMX"] = ePX;
		entryMap["POMY"] = ePY;
		entryMap["BEGINFRAME"] = eBF;
		entryMap["NUMOFFRAMES"] = eNOF;
		entryMap["BATCHSIZE"] = eBS;
		entryMap["BOGPATH"] = eBOGP;
		entryMap["PASSPROBABILITY"] = ePAP;

		string line;
		while(getline(config_file, line))
		{
			size_t space_position = line.find( " " );
			string config_line = line.substr( 0, space_position );
			space_position++;
			switch ( entryMap[config_line] )
			{
				case eSN:
					scenario_name = line.substr( space_position, line.size() );
					sn = true;
					break;
				case ePP:
					proba_path = line.substr( space_position, line.size() );
					pp = true;
					break;
				case eIP:
					image_path = line.substr( space_position, line.size() );
					ip = true;
					break;
				case eBP:
					background_path = line.substr( space_position, line.size() );
					bp = true;
					break;
				case ePF:
					pom_file = line.substr( space_position, line.size() );
					pf = true;
					break;
				case eOP:
					output_path = line.substr( space_position, line.size() );
					op = true;
					break;
				case ePX:
					pom_x = lexical_cast<int>( line.substr( space_position, line.size() ) );
					px = true;
					break;
				case ePY:
					pom_y = lexical_cast<int>( line.substr( space_position, line.size() ) );
					py = true;
					break;
				case eBF:
					begin_frame = lexical_cast<int>( line.substr( space_position, line.size() ) );
					bf = true;
					break;
				case eNOF:
					num_of_frames = lexical_cast<int>( line.substr( space_position, line.size() ) );
					nof = true;
					break;
				case eBS:
					batch_size = lexical_cast<int>( line.substr( space_position, line.size() ) );
					bs = true;
					break;
				case eBOGP:
					bog_path = lexical_cast<string>( line.substr( space_position, line.size() ) );
					bogp = true;
					break;
				case ePAP:
					passProb = lexical_cast<double>( line.substr( space_position, line.size() ) );
					pap = true;
					break;
				default:
					break;
			}
		}
		if ( sn == false || pp == false || ip == false || bp == false || pf == false || op == false || px == false 
			|| py == false || bf == false || nof == false || bs == false || bogp == false || pap == false )
		{
			throw vbl::runtime_error( "[readConfigFile] Not all neccesary fields found in file." );
		}
	}
}

void readPOMFile( string path, int frame, vector<double> & proba )
{
	string frameNumber = lexical_cast<string>(frame);
# ifndef USE_OLD_DAT_NOTATION
	string fileName = path + frameNumber + "-proba.dat";
# else
	string fileName = path + "proba-f" + frameNumber + ".dat";
#endif
	ifstream file(fileName.c_str());

	if(!file.is_open())
	{
		throw vbl::runtime_error( "[readPOMFile] Proba file not found: " + fileName );
	} 
	else 
	{
		string line;
		while(getline(file, line))
		{
			// find 'space'-character, value behind it is probability, value before it is location
			size_t firstSpacePos = line.find( " " );
			line = line.substr( firstSpacePos + 1, line.size() );
			
			double probability = lexical_cast<double>(line);
			proba.push_back(probability);
		}
		file.close();
	}
}

void readPOMfiles( string path, int begin_frame, int num_of_frames, vector<vector<double>> & node_prob )
{
	cout << "...Reading files..." << endl;

	boost::progress_display progress( num_of_frames );
	for( int frame = begin_frame ; frame < begin_frame + num_of_frames ; frame++)
	{
		vector<double> proba;
		try
		{
			readPOMFile(path, frame, proba);
		} catch( vbl::runtime_error e ) 
		{
			cout << e.what() << endl;
			exit(-1);
		}
		node_prob.push_back(proba);
		++progress;
	}
}

void savePaths( vector<vector<location>> paths , int pomX , unsigned int numOfFrames, vector<vector<int>> & fullPaths , 
			   string outputPath ) 
{
	
	for( unsigned int i = 0 ; i < paths.size() ; i++ )
	{
		vector<int> path;
		for( unsigned int j = 0 ; j < numOfFrames ; j++ ) 
		{
			path.push_back(0);
		}
		fullPaths.push_back(path);
	}

	for( unsigned int i = 0 ; i < paths.size() ; i++ ) 
	{
		vector<location> path = paths[i];
		for( unsigned int j = 1 ; j < path.size()-1 ; j++ ) 
		{
			int loc = (path[j].y-1) * pomX + path[j].x;
			int ts = path[j].ts;
			//int loc = ( ( path[j] - 1 ) % numOfLocations ) + 1;
			//int ts = (int) floor( ((double) path[j]-1) / numOfLocations );
			fullPaths[i][ts] = loc;
		}
	}

	ofstream outFile;
	string fileLoc = outputPath + "paths.txt";
	outFile.open(fileLoc.c_str());
	for( unsigned int i = 0 ; i < fullPaths.size() ; i++ ) 
	{
		vector<int> path = fullPaths[i];
		for( unsigned int j = 0 ; j < path.size() ; j++ ) 
		{
			outFile << path[j] << " ";
		}
		outFile << endl;
	}
	outFile.close();
}

void getFilesPerCamera( const string& directoryName, vector< vector< string > >& files, int firstFrame, int finalFrame, 
					   int numOfCams )
{
	namespace bf = boost::filesystem;
	bf::path dirPath( directoryName, bf::native );
	if ( !bf::exists( dirPath ) )
	{
		return;
	}

	MCG::MCGDataset fileList(dirPath.string(), firstFrame, finalFrame);
	for( int i = 0 ; i < numOfCams; ++i)
	{
		vector<bf::path> oneCameraList;
		fileList.list_imagefiles(oneCameraList, vbl::math::power(2,i)); // TODO use int to flag of camera

		BOOST_FOREACH( bf::path& path, oneCameraList )
		{
			files[i].push_back(path.string());
		}
	}
}

void getFilesPerCamera( const string& directoryName, vector< vector< string > >& files ) 
{
	namespace bf = boost::filesystem;
	bf::path dirPath( directoryName, bf::native );
	if ( !bf::exists( dirPath ) )
	{
		return;
	}
	
	const boost::regex my_filter( "(07|14|19)_([0-9]+)_[0-9]+\\.[0-9]+\\.raw" );
	bf::directory_iterator itrEnd;
	for ( bf::directory_iterator itr( dirPath ); itr != itrEnd; ++itr )
	{
		if ( !bf::is_directory( *itr ) )
		{
			boost::smatch match;
			
			string& fileName = itr->leaf();

			if( boost::regex_match( fileName, match, my_filter ) )
			{
				int cam;
				
				// match camera number
				try
				{
					string s_match(match[1].first, match[1].second);
					cam = lexical_cast<int>(s_match); // string to int conversion					
				}
				catch(const bad_lexical_cast &)
				{
					// ok, couldn't find the camera number, trying to interpret an empty string
					// continue with next file
					continue;
				}

				switch( cam )
				{
					case 14: files[0].push_back( fileName ); break;
					case 19: files[1].push_back( fileName ); break;
					case 7: files[2].push_back( fileName ); break;
				}
			}			
		}
	}
}

void parseLine( string line , vector<vector<rectangle>> & pomLocations )
{
	size_t recPos = line.find("RECTANGLE");
	if ( recPos == string::npos ) 
	{
		// contains no rectangle information
		return;
	} 
	else 
	{
		rectangle r;
		// contains rectangle information
		size_t firstSpacePos = line.find( " " );
		size_t secondSpacePos = line.find( " " , firstSpacePos + 1 );
		size_t thirdSpacePos = line.find( " " , secondSpacePos + 1 );
			
		string cam = line.substr( firstSpacePos + 1 , secondSpacePos - firstSpacePos - 1 );
		string loc = line.substr( secondSpacePos + 1 , thirdSpacePos - secondSpacePos - 1 );
		string rec = line.substr( thirdSpacePos + 1 , line.size());

		int camNr = lexical_cast<int>( cam );
		int locNr = lexical_cast<int>( loc );

		if ( rec == "notvisible" )
		{
			r.isVisible = false;
			r.xmin = -1;
			r.xmax = -1;
			r.ymin = -1;
			r.ymax = -1;
		} 
		else 
		{
			r.isVisible = true;
			size_t xminLoc = rec.find( " " );
			size_t yminLoc = rec.find( " " , xminLoc + 1 );
			size_t xmaxLoc = rec.find( " " , yminLoc + 1 );

			string xminStr = rec.substr( 0 , xminLoc );
			string yminStr = rec.substr( xminLoc + 1 , yminLoc - xminLoc - 1 );
			string xmaxStr = rec.substr( yminLoc + 1 , xmaxLoc - yminLoc - 1 );
			string ymaxStr = rec.substr( xmaxLoc + 1 , rec.size() );

			r.xmin = lexical_cast<int>( xminStr );
			r.ymin = lexical_cast<int>( yminStr );
			r.xmax = lexical_cast<int>( xmaxStr );
			r.ymax = lexical_cast<int>( ymaxStr );
		}

		pomLocations[ camNr ][ locNr ] = r;
	}

}

void readPomFile( string pomFile , vector<vector<rectangle>> & pomLocations )
{
	ifstream file(pomFile.c_str());

	if(!file.is_open())
	{
		throw vbl::runtime_error( "[readPomFile] POM file not found:" + pomFile );
		exit(1);
	} 
	else 
	{
		string line;
		while(getline(file, line))
		{
			parseLine( line , pomLocations );
		}
		file.close();
	}
}

img::Triple<> getHeatmapColor( double value ) 
{
	int r, g, b;

	if ( value > 0.75 && value <= 1 )
	{
		r = 255;
		b = 0;
		g = int((1-((value-0.75) * 4)) * 255);
	} 
	else if ( value > 0.5 ) 
	{
		g = 255;
		b = 0;
		r = int(((value-0.5)*4) * 255);
	} 
	else if ( value > 0.25 ) 
	{
		r = 0;
		g = 255;
		b = int((1-((value-0.25) * 4)) * 255);
	} 
	else if ( value > 0 ) 
	{
		r = 0;
		b = 255;
		g = int(value*4*255);
	}

	return img::Triple<>( r , g , b );
}

int calculateSurface( rectangle r ) 
{
	return ( r.xmax - r.xmin ) * ( r.ymax - r.ymin );
}

void saveImages( vector<vector<int>> paths, vector<vector<double>> probabilities , string imagePath , string pomFile, 
				int beginFrame , int numOfFrames , int numOfLocations , int pomX, string outputPath , string backgroundPath, 
				string bog_path )
{
	cout << "Writing images to disc." << endl;
	//int imageWidth = 1024;
	//int imageHeight = 768;
	// TODO set these parameters in config file!
	int imageWidth = 752;
	int imageHeight = 560;
	const int numOfCams = 3;

	vector< img::Triple<> > colors;
	colors.push_back(img::Triple<>(255,0,0));	// red
	colors.push_back(img::Triple<>(0,255,0));	// green
	//colors.push_back(img::Triple<>(0,0,255));	// blue
	colors.push_back(img::Triple<>(255,255,0)); // yellow
	colors.push_back(img::Triple<>(0,255,255));	// cyan
	colors.push_back(img::Triple<>(255,0,255)); // purple
	colors.push_back(img::Triple<>(255,165,0)); // orange
	colors.push_back(img::Triple<>(165,42,42)); // brown
	colors.push_back(img::Triple<>(0,255,127)); // spring green
	colors.push_back(img::Triple<>(255,192,203)); // pink
	colors.push_back(img::Triple<>(127,255,212)); // aquamarine
	colors.push_back(img::Triple<>(218,165,32)); // goldenrod
	colors.push_back(img::Triple<>(178,34,34)); // firebrick
	colors.push_back(img::Triple<>(205,133,63)); // peru
	colors.push_back(img::Triple<>(238,130,238)); // violet
	
# ifndef USE_CAS_DATASET
	double rot [] = { 2.9477621582585201 , -1.6764118889390500 , -5.7642762038006197 , 2.3607981090325212 };
#else
	double rot [] = { -20.3973 , -5.82713 , -2.24835 };
#endif

	vector< util::Array2D< double > > distMapX_;
	vector< util::Array2D< double > > distMapY_;

	distMapX_.resize( numOfCams, util::Array2D< double >( imageWidth, imageHeight ) );
	distMapY_.resize( numOfCams, util::Array2D< double >( imageWidth, imageHeight ) );
	
	calib::BogData bogData[numOfCams];
	cas::help::readBogData( bog_path, bogData );

	for( int cam = 0; cam < numOfCams ; ++cam )
	{
		cas::help::computeUndistortMap( bogData[cam], distMapX_[cam], distMapY_[cam] );
	}

	// TODO clean up this method, pass on variables and remove hard coded variables;
	vector< vector< string > > filesPerCamera( numOfCams );

#ifndef USE_OLD_FILESYSTEM
	getFilesPerCamera( imagePath, filesPerCamera, beginFrame, beginFrame + numOfFrames, numOfCams );
#else
	getFilesPerCamera( imagePath, filesPerCamera );
#endif

	vector< img::ImageRGB > inputIms( numOfCams , img::ImageRGB( imageWidth, imageHeight ) );
	
	vector<vector<rectangle>> pomLocations;
	for (int i = 0 ; i < numOfCams ; i++ ) 
	{
		vector<rectangle> toAdd (numOfLocations);
		pomLocations.push_back(toAdd);
	}
	readPomFile( pomFile , pomLocations );
	boost::progress_display progress( numOfFrames );
	for ( int i = 0 ; i < numOfFrames ; i++ ) 
	{
		vector< img::ImageRGB > imageVec;

		int frame = beginFrame + i;
		string frameNumber;
		if ( frame < 1000 ) {
			frameNumber = "0" + lexical_cast<string>(frame);
		} else {
			frameNumber = lexical_cast<string>(frame);
		}

		for( int cam = 0; cam < numOfCams; ++cam ) 
		{
			img::ImageG imRaw( imageWidth, imageHeight );
#ifndef USE_OLD_FILESYSTEM
			img::io::readRAW( filesPerCamera[cam][ i ], imRaw, imRaw.width(), imRaw.height() ); 
#else
			img::io::readRAW( imagePath + "/" + filesPerCamera[cam][ beginFrame + i ], imRaw, imRaw.width(), imRaw.height() ); 
#endif
			img::proc::demosaicPixelGrouping( imRaw, inputIms[cam] );
			cas::help::undistortImage( inputIms[cam], distMapX_[cam], distMapY_[cam] );
			img::rotateSafe< img::InterpolatorBilinear >( inputIms[cam], imageWidth/2, imageHeight/2, rot[cam] );
			img::ImageRGB im = inputIms[cam];

			img::ImageRGB background;
#ifndef USE_CAS_DATASET
			string backgroundImPath = backgroundPath + lexical_cast<string>(frame) + "_" + lexical_cast<string>(cam) + 
				"-result.png";
#else
			string backgroundImPath = backgroundPath + "result-f" + lexical_cast<string>(frame) + "-c" + 
				lexical_cast<string>(cam) + ".png";
#endif
			try
			{
				img::io::read(backgroundImPath , background );
			} catch( vbl::runtime_error e ) 
			{
				cout << " Could not read background file: " << e.what() << endl;
				exit(1);
			}
			img::Triple<> maskColor(0,204,153);
			
			for ( unsigned int j = 0 ; j < pomLocations[cam].size() ; j++ ) {
				rectangle r = pomLocations[cam][j];
				double value = probabilities[i][j];
				img::Triple<> color = getHeatmapColor( value );
				if ( r.isVisible ) {
					img::drawCross( im , int((r.xmin+r.xmax) / 2.0) , r.ymax, color, 3, 3 );
				}
			}
			
			// AND REMOVE THIS
			/*
			//util::Window win("Cut out");
			for ( unsigned int j = 0 ; j < pomLocations[cam].size() ; j++ ) {
				rectangle r = pomLocations[cam][j];
				if ( r.isVisible ) {
					img::ImageRGB imageCutOut( r.xmax - r.xmin , r.ymax - r.ymin );
					img::copy( im , r.xmin , r.ymin , r.xmax - r.xmin , r.ymax - r.ymin , imageCutOut);
					img::ImageRGB backgroundCutOut( r.xmax - r.xmin , r.ymax - r.ymin );
					img::copy( background , r.xmin , r.ymin , r.xmax - r.xmin , r.ymax - r.ymin , backgroundCutOut );
					
					img::copyImageForeground( imageCutOut, backgroundCutOut, maskColor, imageCutOut );
					//win.showImage(imageCutOut);
					//win.waitForKey();

					//copyImageForeground( const Image<T, AP1>& imBg, const Image<T, AP2>& imFg, const T& mask_val, Image<T, AP3>& imOut );
					img::Triple<> avgCol = calcAvgColor( imageCutOut );
					img::drawCross( im , int((r.xmin+r.xmax) / 2.0) , r.ymax, avgCol, 3, 3 );
				}
			}
			*/
			//
		
			vector<pair<int,int>> toSort;

			for ( unsigned int j = 0 ; j < paths.size() ; j++ ) {
				int loc = paths[j][i];
				if ( loc != 0 ) {
					rectangle r = pomLocations[cam][loc-1];
					if ( r.xmax != -1 ) {
						int surface = calculateSurface(r);
						toSort.push_back(pair<int,int>(surface,j));
					}
				}
			}
			sort (toSort.begin(), toSort.end());

			vector<cutOutInfo> toAdd;
			for ( unsigned int j = 0 ; j < toSort.size() ; j++ ) {
				int loc = paths[toSort[j].second][i];
				if ( loc != 0 ) {
					rectangle r = pomLocations[cam][loc-1];
					img::ImageRGB backgroundCutOut( r.xmax - r.xmin , r.ymax - r.ymin );
					img::ImageRGB imageCutOut( r.xmax - r.xmin , r.ymax - r.ymin );
					img::Triple<> pathColor = colors[ (toSort[j].second % colors.size() )];
					try
					{
						img::copy( background , r.xmin , r.ymin , r.xmax - r.xmin , r.ymax - r.ymin , backgroundCutOut );
						img::equals( backgroundCutOut, maskColor, pathColor, img::Triple<>(0,0,0) );
						img::copy( im , r.xmin , r.ymin , r.xmax - r.xmin , r.ymax - r.ymin , imageCutOut);
						overlay(imageCutOut,backgroundCutOut, 0.5, true);	
					} catch ( vbl::runtime_error e )
					{
						cout << "Unable overlay part of background onto part of image. Error: " << e.what() << endl;
						exit(2);
					}
					
					cutOutInfo coi;
					coi.r = r;
					coi.pathNr = toSort[j].second;
					coi.imageCutOut = imageCutOut;
					toAdd.push_back(coi);
					
				}
			}

			for ( unsigned int j = 0 ; j < toAdd.size() ; j++ ) {
				cutOutInfo coi = toAdd[j];
				img::copy( coi.imageCutOut, im, coi.r.xmin, coi.r.ymin );
				img::drawBox( im, coi.r.xmin, coi.r.ymin, coi.r.xmax, coi.r.ymax, colors[ (coi.pathNr % colors.size() )]);
			}

			imageVec.push_back( im );

		}
		
		++progress;
		img::ImageRGB bigIm( imageVec[0].width() * 2 , imageVec[0].height() * 2 );
		if ( numOfCams == 3 )
		{
			img::copy( imageVec[0] , bigIm , 0 , 0 );
			img::copy( imageVec[1] , bigIm , imageVec[1].width() , 0 );
			img::copy( imageVec[2] , bigIm , imageVec[2].width() / 2 , imageVec[2].height() );
		} 
		else if ( numOfCams == 4 )
		{
			img::copy( imageVec[0] , bigIm , 0 , 0 );
			img::copy( imageVec[1] , bigIm , imageVec[1].width() , 0 );
			img::copy( imageVec[2] , bigIm , 0 , imageVec[1].height() );
			img::copy( imageVec[3] , bigIm , imageVec[1].width() , imageVec[1].height() );
		}
		img::resample( bigIm , int(imageVec[0].width()*1.5) , int(imageVec[0].height()*1.5) , true );

		string filename = outputPath + frameNumber + ".jpg";
		img::io::write( filename , bigIm );
	}

}

int main(int argc, char* argv[])
{
	if( argc != 2 )
	{
		throw vbl::runtime_error( "[main] Invalid number of arguments. Please (only) specify config file." );
	}

	bool bSaveImages = false;
	string config_file_path = argv[1];
	
	string scenario_name, proba_path, image_path, background_path, pom_file, output_path, bog_path;
	int pom_x, pom_y, begin_frame, num_of_frames, batch_size;
	double pass_prob;

	try
	{
		readConfigFile(config_file_path, scenario_name, proba_path, image_path, background_path, pom_file, output_path, 
		bog_path, pom_x, pom_y, begin_frame, num_of_frames, batch_size, pass_prob);
	} 
	catch( vbl::runtime_error e ) 
	{
		cout << e.what() << endl;
		exit(1);
	}

	cout << "-------------------------------------------------------------------------------" << endl;
	cout << "Your parameters are as follows:" << endl;
	cout << "Scenario name: " << scenario_name << endl;
	cout << "POMs: " << proba_path << endl;
	cout << "Images: " << image_path << endl;
	cout << "Backgrounds: " << background_path << endl;
	cout << "POM config file: " << pom_file << endl;
	cout << "Output: " << output_path << endl;
	cout << "Camera calibration: " << bog_path << endl;
	cout << "POM grid size: " << pom_x << " x " << pom_y << endl;
	cout << "Begin frame: " << begin_frame << endl;
	cout << "Number of frames: " << num_of_frames << endl;
	cout << "Bacth size: " << batch_size << endl;
	cout << "Person acceptence threshold: " << pass_prob << endl;
	cout << "-------------------------------------------------------------------------------" << endl << endl;

	vector<vector<double>> node_prob;
	readPOMfiles( proba_path, begin_frame, num_of_frames, node_prob );

	ksp::KSP KSPob( node_prob, pom_x, pom_y, pass_prob, begin_frame, num_of_frames, batch_size );

	vector<vector<location>> paths;

	KSPob.findKSP( paths );

	output_path = output_path + scenario_name + "/";
	if( ! boost::filesystem::exists( output_path ) ) 
	{
		boost::filesystem::create_directory( output_path );
	}

	vector<vector<int>> convertedPaths;
	savePaths( paths , pom_x , num_of_frames, convertedPaths , output_path );
	if ( bSaveImages )
	{
		saveImages( convertedPaths, node_prob, image_path, pom_file, begin_frame, num_of_frames, pom_x*pom_y, 
			pom_x, output_path, background_path, bog_path );
	}

	return 0;
}

